package cn.com.okgo.request.base;

import android.text.TextUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import cn.com.okgo.OkGo;
import cn.com.okgo.cache.CacheMode;
import cn.com.okgo.callback.HttpCallback;
import cn.com.okgo.model.HttpHeaders;
import cn.com.okgo.model.HttpParams;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

/**
 * Created by luwenlong on 2017/8/28.
 */

public abstract class BaseRequest<T, R extends BaseRequest> {

    protected String baseUrl;             //站点      (可不填写)
    protected List<String> baseUrls;      //站点列表  (可不填写)
    protected String url;                 //请求地址  (可直接写全路径)
    protected Object tag;                 //用于标记请求
    protected long readTimeOut;           //读取时间
    protected long writeTimeOut;          //写入时间
    protected long connectTimeout;        //超时时间
    protected int maxRetry;               //最大重试次数
    protected long delay;                 //重试时间
    protected long increaseDelay;         //叠加时间
    protected boolean needChangeService;  //是否需要优选站点
    protected CacheMode cacheMode = CacheMode.NO_CACHE; //缓存模式 默认不缓存

    protected HttpHeaders headers = new HttpHeaders(); // 请求头
    protected HttpParams params = new HttpParams();    // body
    private transient HttpCallback callback;

    protected BaseRequest(String url) {
        this.url = url;
        OkGo go = OkGo.getInstance();
        //默认添加 Accept-Language
        String acceptLanguage = HttpHeaders.getAcceptLanguage();
        if (!TextUtils.isEmpty( acceptLanguage ))
            headers( HttpHeaders.HEAD_KEY_ACCEPT_LANGUAGE, acceptLanguage );
        //默认添加 User-Agent
        String userAgent = HttpHeaders.getUserAgent();
        if (!TextUtils.isEmpty( userAgent )) headers( HttpHeaders.HEAD_KEY_USER_AGENT, userAgent );
        //添加公共请求参数
        if (go.getCommonParams() != null) params( go.getCommonParams() );
        if (go.getCommonHeaders() != null) headers( go.getCommonHeaders() );
    }

    /**
     * 根据不同的请求方式和参数，生成不同的RequestBody
     */
    protected abstract RequestBody generateRequestBody();

    /**
     * 根据不同的请求方式，将RequestBody转换成Request对象
     */
    public abstract okhttp3.Request generateRequest(RequestBody requestBody);

    /**
     * 构建请求体，返回call对象
     *
     * @return
     */
    public okhttp3.Call generateCall() {
        Request request;
        RequestBody requestBody = generateRequestBody();
        if (requestBody != null) {
            ProgressRequestBody<T> progressRequestBody = new ProgressRequestBody<>( requestBody, callback );
            request = generateRequest( progressRequestBody );
        } else {
            request = generateRequest( null );
        }

        if (readTimeOut <= 0 && writeTimeOut <= 0 && connectTimeout <= 0) {
            return OkGo.getInstance().getOkHttpClient().newCall( request );
        } else {
            OkHttpClient.Builder builder = OkGo.getInstance().getOkHttpClient().newBuilder();
            if (readTimeOut > 0) builder.readTimeout( readTimeOut, TimeUnit.SECONDS );
            if (writeTimeOut > 0) builder.writeTimeout( writeTimeOut, TimeUnit.SECONDS );
            if (connectTimeout > 0) builder.connectTimeout( connectTimeout, TimeUnit.SECONDS );
            return builder.build().newCall( request );
        }

    }

    /**
     * 非阻塞方法，异步请求，但是回调在子线程中执行
     */
    public <T> void execute(HttpCallback<T> callback) {
        this.callback = callback;
        callback.execute( this, callback );
    }
    //******************************** 基本参数设置 **********************************

    public R baseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
        return (R) this;
    }

    public R baseUrls(List<String> baseUrls) {
        this.baseUrls = baseUrls;
        return (R) this;
    }

    public R tag(Object tag) {
        this.tag = tag;
        return (R) this;
    }

    public R readTimeOut(long readTimeOut) {
        this.readTimeOut = readTimeOut;
        return (R) this;
    }

    public R writeTimeOut(long writeTimeOut) {
        this.writeTimeOut = writeTimeOut;
        return (R) this;
    }

    public R connectTimeout(long connTimeOut) {
        this.connectTimeout = connTimeOut;
        return (R) this;
    }

    public R maxRetry(int maxRetry) {
        this.maxRetry = maxRetry;
        return (R) this;
    }

    public R delay(long delay) {
        this.delay = delay;
        return (R) this;
    }


    public R increaseDelay(long increaseDelay) {
        this.increaseDelay = increaseDelay;
        return (R) this;
    }

    public R cacheMode(CacheMode cacheMode) {
        this.cacheMode = cacheMode;
        return (R) this;
    }

    public R needChangeService(boolean needChangeService) {
        this.needChangeService = needChangeService;
        return (R) this;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public List<String> getBaseUrls() {
        return baseUrls;
    }

    public String getUrl() {
        return url;
    }

    public Object getTag() {
        return tag;
    }

    public long getReadTimeOut() {
        return readTimeOut;
    }

    public long getWriteTimeOut() {
        return writeTimeOut;
    }

    public long getConnectTimeout() {
        return connectTimeout;
    }

    public int getMaxRetry() {
        return maxRetry;
    }

    public long getDelay() {
        return delay;
    }

    public long getIncreaseDelay() {
        return increaseDelay;
    }

    public boolean isNeedChangeService() {
        return needChangeService;
    }

    public CacheMode getCacheMode() {
        return null == cacheMode ? CacheMode.NO_CACHE : cacheMode;
    }

    //******************************** header参数设置 **********************************

    public R headers(HttpHeaders headers) {
        this.headers.put( headers );
        return (R) this;
    }

    public R headers(String key, String value) {
        headers.put( key, value );
        return (R) this;
    }

    public R removeHeader(String key) {
        headers.remove( key );
        return (R) this;
    }

    public R removeAllHeaders() {
        headers.clear();
        return (R) this;
    }

    public HttpHeaders getHeaders() {
        return headers;
    }

    //******************************** body参数设置 **********************************

    public R params(HttpParams params) {
        this.params.put( params );
        return (R) this;
    }

    public R params(Map<String, String> params) {
        this.params.put( params );
        return (R) this;
    }

    public R params(String key, String value) {
        params.put( key, value );
        return (R) this;
    }

    public R params(String key, int value) {
        params.put( key, value );
        return (R) this;
    }

    public R params(String key, float value) {
        params.put( key, value );
        return (R) this;
    }

    public R params(String key, double value) {
        params.put( key, value );
        return (R) this;
    }

    public R params(String key, long value) {
        params.put( key, value );
        return (R) this;
    }

    public R params(String key, char value) {
        params.put( key, value );
        return (R) this;
    }

    public R params(String key, boolean value) {
        params.put( key, value );
        return (R) this;
    }

    public HttpParams getParams() {
        return params;
    }

}
